<template>
  <!--  给下拉列表设置ref属性 -->
  <div class="dropdown" ref="dropdownRef">
    <button class="btn btn-outline-light dropdown-toggle" type="button" id="dropdownMenuButton1"
    data-bs-toggle="dropdown" aria-expanded="false" @click="toggleOpen">
      {{title}}
    </button>
    <ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1" :style="{display: 'block'}" v-if="isOpen">
      <!-- 插槽 -->
      <slot></slot>
    </ul>
  </div>
</template>
<script lang="ts">
import { defineComponent, onUnmounted, ref, watch } from 'vue'
import mitt from 'mitt'
import useClickOutside from '../hooks/useClickOutside'

export const emitter = mitt()
export default defineComponent({
  name: 'Dropdown',
  props: {
    title: {
      type: String,
      required: true
    }
  },
  emits: ['item-clicked'],
  setup (props, context) {
    // 控制下拉菜单
    const isOpen = ref(false)
    // 获取组件节点对象，通过定义ref响应式对象在return中返回，并在组件根节点上添加ref="dropdownRef"属性
    const dropdownRef = ref<null | HTMLElement>(null)
    const toggleOpen = () => {
      // 开关值取反
      isOpen.value = !isOpen.value
    }
    // 定义发送事件的函数
    const dropDownItemClicked = (e: any) => {
      if (e.props.closeAfterClick) {
        isOpen.value = false
      }
      context.emit('item-clicked', e)
    }
    emitter.on('dropdown-item-clicked', dropDownItemClicked)
    onUnmounted(() => {
      emitter.off('dropdown-item-clicked', dropDownItemClicked)
    })

    const isClickOutside = useClickOutside(dropdownRef)
    // 通过监听isClickOutside响应式的值来判断是否执行收回下来组件
    watch(isClickOutside, () => {
      // 鼠标点击在下拉组件外面，并且isOpen.value=true(下拉组件已经打开)，则收回下来组件
      if (isClickOutside.value && isOpen.value) {
        isOpen.value = false
      }
    })
    return {
      isOpen,
      toggleOpen,
      dropdownRef
    }
  }
})
</script>
